#include <QtGui>
#include <QtSql>
#include "listsstore.h"
#include "rijndael.h"

listsStore::listsStore(QObject *parent):QObject(parent)
{
}

bool listsStore::open(QWidget *parent, const QString &pwd)
{
	if(!QDir().exists(qApp->property("dataDir").toString())) QDir().mkpath(qApp->property("dataDir").toString());
	if(!QFile::exists(qApp->property("dataDir").toString()+"/lists.db")){
		if(QFile::exists(qApp->property("dataDir").toString()+"/lists.cdb")){
			// db is encrypted
			// do decrypt
			decrypt(qApp->property("dataDir").toString()+"/lists.cdb",qApp->property("dataDir").toString()+"/lists.db",pwd);

			if(!isSQLiteDB(qApp->property("dataDir").toString()+"/lists.db")){
				QFile::remove(qApp->property("dataDir").toString()+"/lists.db");
				QMessageBox::warning(parent,tr("Warning"),tr("Incorrect unlock code!"));
				return false;
			}
		}else{
			// db doesn't initialized
			{
				QSqlDatabase dbc0= QSqlDatabase::addDatabase("QSQLITE", "INIT");
				dbc0.setDatabaseName(qApp->property("dataDir").toString()+"/lists.db");
				if(!dbc0.open()){
					qCritical()<<"Can't create database!";
					return false;
				}
				QSqlQuery q(dbc0);
				q.prepare("CREATE TABLE IF NOT EXISTS purchase ("
						  "pDate TEXT, "
						  "pList TEXT, "
						  "pShop INTEGER, "
						  "pSec TEXT, "
						  "pCat TEXT, "
						  "pTitle TEXT, "
						  "pPrcP REAL, "
						  "pCntP REAL, "
						  "pPrcB REAL, "
						  "pCntB REAL, "
						  "pJoy REAL, "
						  "pDone INTEGER)");
				if(!q.exec()){
					qCritical()<<"Can't create database(error during table 'purchase' creation)!";
					return false;
				}

				q.prepare("CREATE TABLE IF NOT EXISTS shop ("
						  "sTitle TEXT NOT NULL, "
						  "sAddress TEXT, "
						  "sGeoLoc TEXT)");
				if(!q.exec()){
					qCritical()<<"Can't create database(error during table 'shop' creation)!";
					return false;
				}

				dbc0.commit();
			}
			QSqlDatabase::removeDatabase("INIT");
		}
	}else{
		if(!isSQLiteDB(qApp->property("dataDir").toString()+"/lists.db")){
			QFile::remove(qApp->property("dataDir").toString()+"/lists.db");
			QMessageBox::warning(parent,tr("Warning"),tr("Incorrect storage format!"));
			return false;
		}
	}

	QSqlDatabase dbc= QSqlDatabase::addDatabase("QSQLITE","CN");
	dbc.setDatabaseName(qApp->property("dataDir").toString()+"/lists.db");
	if(!dbc.open()){
		qCritical()<<"Can't open database!";
		return false;
	}
	QSqlQuery update(dbc);
	update.prepare("UPDATE purchase SET pDone=1 WHERE pDone='Y'");
	update.exec();
	update.prepare("UPDATE purchase SET pDone=0 WHERE pDone='N'");
	update.exec();

	update.prepare("CREATE TABLE IF NOT EXISTS listCfg(pDate TEXT, pList TEXT, attr TEXT, val TEXT)");
	if(!update.exec()){
		qCritical()<<"Can't create database(error during table 'listCfg' creation)!";
		return false;
	}
	update.prepare("CREATE TABLE IF NOT EXISTS headerState(hid INTEGER PRIMARY KEY, state TEXT)");
	if(!update.exec()){
		qCritical()<<"Can't create database(error during table 'headerState' creation)!";
		return false;
	}

	// import header state data from 'listSettings' table
	QSqlQuery setHS(dbc);
	setHS.prepare("REPLACE INTO headerState(hid,state) VALUES(:H,:S)");
	QSqlQuery setHSL(dbc);
	setHSL.prepare("REPLACE INTO listCfg(pDate, pList, attr, val) VALUES(:D,:L,:A,:V)");

	int maxR= 0;
	update.prepare("SELECT count(*) FROM listSettings");
	if(update.exec() && update.next()) maxR= update.value(0).toInt();

	update.prepare("SELECT pDate, pList, headerState FROM listSettings");
	if(update.exec()){
		QProgressDialog progress(parent);
		progress.setWindowTitle(tr("Update storage format"));
		progress.setLabelText(tr("Please wait..."));
		progress.setCancelButton(0);
		QProgressBar *pb= new QProgressBar(&progress);
		pb->setTextVisible(false);
		pb->setAlignment(Qt::AlignCenter);
		progress.setBar(pb);
		progress.setRange(0,maxR);
		progress.setWindowFlags(Qt::Dialog|Qt::CustomizeWindowHint|Qt::WindowTitleHint);
		progress.setWindowModality(Qt::WindowModal);
		progress.show();
		while(update.next()){
			progress.setValue(progress.value()+1);
			QApplication::processEvents();
			QByteArray hs= update.value(2).toString().toAscii();
			int hid= qChecksum(hs.data(),hs.size());
			setHS.bindValue(":H",hid);
			setHS.bindValue(":V",update.value(2));
			if(!setHS.exec()) continue;
			setHSL.bindValue(":D",update.value(0));
			setHSL.bindValue(":L",update.value(1));
			setHSL.bindValue(":A","headerState");
			setHSL.bindValue(":V",hid);
			setHSL.exec();
		}
		update.prepare("DROP TABLE IF EXISTS listSettings");
		update.exec();
		update.prepare("VACUUM");
		update.exec();
	}
	return true;
}

bool listsStore::close(const QString& pwd)
{
	QSqlDatabase::removeDatabase("CN");

	if(pwd.trimmed().isEmpty()) return true;
	// crypt DB
	if(0 != encrypt(qApp->property("dataDir").toString()+"/lists.db",qApp->property("dataDir").toString()+"/lists.cdb",pwd)) return false;
	if(0 != encrypt(qApp->property("dataDir").toString()+"/lists.cdb",qApp->property("dataDir").toString()+"/lists.db",pwd)) return false;
	if(!QFile::remove(qApp->property("dataDir").toString()+"/lists.db")) return false;


	return true;
}

bool listsStore::isSQLiteDB(const QString& dbFilePath)
{
	QByteArray mgc= "SQLite format 3";
	QFile f(dbFilePath);
	if(!f.open(QIODevice::ReadOnly)) return false;
	QByteArray mgcs= f.read(15);
	f.close();
	if(mgcs != mgc) return false;
	return true;
}
